#ifndef __SELECT_SVR_H__
#define __SELECT_SVR_H__

#include <iostream>
#include <sys/select.h>
#include <sys/time.h>
#include <string>
#include "Log.hpp"
#include "Sock.hpp"

#define BITS 8
#define NUM (sizeof(fd_set) * BITS)
#define FD_NONE -1 // 表示初始化状态

using namespace std;

// 使用select进行监控，对多个文件描述符进行管理

class SelectServer
{
public:
    SelectServer(const uint16_t &port = 8080)
        : _port(port)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(DEBUG, "%s", "create base socket success");
        for (int i = 0; i < NUM; i++)
            _fd_array[i] = FD_NONE;
        // 规定_fd_array[0]=_listensock;
        _fd_array[0] = _listensock;
    }

    void Start()
    {
        // fd_set rfds;
        // FD_ZERO(&rfds);

        struct timeval timeout = {5, 0};
        // //每隔5秒初始化一次// timeout是输入输出型的，每被初始化后，就变为0，0了
        while (true)
        {
            struct timeval timeout = {0, 0};

            // int sock=Sock::Accept(listensock, ...);
            // FD_SET(_listensock, &rfds); // 将listensock添加到读文件描述符集中

            // int n = select(listensock + 1, &rfds, nullptr, nullptr, &timeout);

            debugPrint();

            fd_set rfds;
            FD_ZERO(&rfds);
            int maxfd = _listensock;
            for (int i = 0; i < NUM; i++)
            {
                if (_fd_array[i] == FD_NONE)
                    continue;
                FD_SET(_fd_array[i], &rfds);
                if (maxfd < _fd_array[i])
                    maxfd = _fd_array[i];
            }

            int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
            switch (n)
            {
            case 0:
                logMessage(DEBUG, "%s", "time out...");
                break;
            case -1:
                logMessage(WARNING, "select error:%d: %s", errno, strerror(errno));
                break;
            default:                                           // 成功
                logMessage(DEBUG, "get a new link event ..."); // 连接建立后，就绪了，需要取走，否则select会一直通知
                HandlerEvent(rfds);
                break;
            }
        }
    }

    ~SelectServer()
    {
        if (_listensock >= 0)
            close(_listensock);
    }

private:
    void HandlerEvent(const fd_set &rfds) // fd_set 是一个集合，可能有多个sock
    {
        for (int i = 0; i < NUM; i++)
        {
            // 去掉不合法的fd
            if (_fd_array[i] == FD_NONE)
                continue;
            // 合法不一定就绪了
            if (FD_ISSET(_fd_array[i], &rfds))
            {
                // 指定的fd， 读事件就绪
                if (_fd_array[i] == _listensock)
                {
                    // 读事件就绪，连接事件到来，accepter
                    Accepter();
                }
                else
                {
                    // 读事件就绪：input事件到来，recv，read
                    Recver(i);
                }
            }
        }
    }

    void Accepter() // 获取新连接
    {
        string clientip;
        uint16_t clientport = 0;
        // listensock上面的读事件就绪，可以进行读取了
        // 获取新连接
        int sock = Sock::Accept(_listensock, &clientip, &clientport); // 不会造成阻塞
        if (sock < 0)
        {
            logMessage(WARNING, "accept error");
            return;
        }
        logMessage(DEBUG, "get a new line success : [%s : %d] %d ", clientip.c_str(), clientport, sock);

        int pos = 1;
        for (; pos < NUM; pos++)
        {
            if (_fd_array[pos] == FD_NONE)
                break;
        }
        if (pos == NUM)
        {
            logMessage(WARNING, "%s:%d", "select server already full, close: %d", sock);
            close(sock);
        }
        else
        {
            _fd_array[pos] = sock;
        }
    }

    void Recver(int pos)
    {

        logMessage(DEBUG, "message in, get IO event: %d", _fd_array[pos]);
        // fd上的数据一定是就绪的，即 本次 不会被阻塞

        /********不能保证一定会读到一个完整的报文，存在bug********/
        char buffer[1024];
        int n = recv(_fd_array[pos], buffer, sizeof(buffer - 1), 0);
        if (n > 0)
        {
            buffer[n] = 0;
            logMessage(DEBUG, "client[%d]# %s", _fd_array[pos], buffer);
        }
        /*****************************************/
        else if (n == 0) // 连接关闭,退出
        {
            logMessage(DEBUG, "client[%d] quit, me too...", _fd_array[pos]);
            // 关闭fd
            close(_fd_array[pos]);
            // 置-1
            _fd_array[pos] = FD_NONE;
        }
        else
        {
            logMessage(WARNING, "%d sock recv error, %d: %s", _fd_array[pos], errno, strerror(errno));
            // 关闭fd
            close(_fd_array[pos]);
            // 置-1
            _fd_array[pos] = FD_NONE;
        }
    }



    void debugPrint()
    {
        cout << "_fd_array[]: ";
        for (int i = 0; i < NUM; i++)
        {
            if (_fd_array[i] == FD_NONE)
                continue;
            cout << _fd_array[i] << " ";
        }
        cout << endl;
    }

private:
    uint16_t _port;
    int _listensock;
    int _fd_array[NUM];
};

#endif